# !/usr/bin/env python
# -*- coding: utf-8 -*-
"""
 -------------------------------------------------
    File Name:     validate_response.py
    Description:   
 -------------------------------------------------
 """
import jsonschema
import requests.models
from deepdiff import DeepDiff
from jsonschema.exceptions import ValidationError

from apitesting.src.models import ResponseModel
from apitesting.common.util.logger import log
from apitesting.common.util.allure_handler import allure_handler


class ValidateResponseAssert:
    """校验响应 Validate Response"""

    def validate_response(
            self,
            responses_model_list: list[ResponseModel],
            response: requests.models.Response
    ) -> None:
        """
        校验响应
        :return:
        """
        # 校验响应状态码, 拿到与响应状态码匹配的响应模型
        responses_model = self.check_response_status_code(response, responses_model_list)

        if responses_model is None:
            log.warning(f"未找到与响应状态码匹配的响应模型，不进行响应校验！！！")
            return

        # 兼容单个数据
        if not isinstance(responses_model.example, (list, dict)):
            raise ValueError(f"示例格式错误：{responses_model.example} is not a list or dict")
        if isinstance(responses_model.example, dict):
            responses_model.example = [responses_model.example]

        # jsonschema校验
        if responses_model.jsonschema:
            self._jsonschema_assertion(response, responses_model)

        # 示例校验：遍历每个example进行校验
        for response_example in responses_model.example:
            is_result_bool: bool = self.difference_response_json(response_example, response.json())
            if is_result_bool:
                log.info(f"响应校验-示例：响应体与预期一致")
                return
        else:
            log.error(f"响应校验-示例：响应体与预期不一致")
            # raise AssertionError(f"响应体与预期不一致")

    @staticmethod
    def check_response_status_code(
            response_data: requests.models.Response,
            responses_model_list: list[ResponseModel]
    ) -> None | ResponseModel:
        """
        校验响应状态码

        :param responses_model_list: 响应模型列表
        :param response_data: 响应数据
        :return:
        """
        for responses_model in responses_model_list:
            if response_data.status_code == responses_model.status_code:
                return responses_model
        return None

    @staticmethod
    def _jsonschema_assertion(
            response: requests.models.Response,
            assert_model: ResponseModel
    ) -> None:
        """
        jsonschema校验
        """
        # assert_content_type = assert_model.content_type
        assert_jsonschema = assert_model.jsonschema

        if not isinstance(assert_jsonschema, dict):
            raise TypeError(f"jsonschema类型错误: {assert_jsonschema} is not a dict")

        try:
            jsonschema.validate(instance=response.json(), schema=assert_jsonschema)
        except ValidationError as e:
            log.debug(f"path: {e.path}")
            log.debug(f"message: {e.message}")
            log.debug(f"schema: {e.schema}")
            log.debug(f"schema_path: {e.schema_path}")
            # log.error(f"返回数据结构与接口定义不一致\n{e.message}")
            # for prop in e.path:
            #     log.error(f"属性路径：{prop}")
            allure_handler.add_step(step="响应校验-schema校验：不通过", var=e.message)

            # raise e

    @staticmethod
    def difference_response_json(json_schema: dict, json_data: dict) -> bool:
        """
        比较响应体与jsonschema
        """
        diff_result = DeepDiff(t1=json_schema, t2=json_data, ignore_order=True)
        diff_result.pop("values_changed", None)  # 值的内容不一样去掉。不需要这么细, 没有则返回None,不报错
        log.debug(f"diff_result: {diff_result}")

        if diff_result:  # diff_result={}，说明校验通过
            log.info(f"响应校验-schema校验：不通过！deepdiff结果：{diff_result}")
            return False
        else:
            log.error(f"schema校验通过：{diff_result}")
            return True
            # raise AssertionError(f"响应体与预期不一致")


ValidateResponse = ValidateResponseAssert()
